package com.verlet.servicefeign.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.util.Assert;

import java.util.Collections;


/**
 * 分布式锁
 */
@Slf4j
public class RedisLock {

    private static RedisTemplate redisTemplate;

    static {
        redisTemplate = (RedisTemplate) SpringBootBeanUtil.getBean("redisTemplate");
        Assert.notNull(redisTemplate, "redisTemple初始化失败");
    }

    public static boolean lock(String key, long timeout) {
        return lock(key, String.valueOf(Thread.currentThread().getId()), timeout);
    }

    public static boolean lock(String key, String value, long timeout) {
        Object result = redisTemplate.execute((RedisCallback<Boolean>) connection ->
                connection.set(key.getBytes(), value.getBytes(), Expiration.seconds(timeout),
                        RedisStringCommands.SetOption.SET_IF_ABSENT));
        if (result != null && (Boolean) result) {
            log.info("{}: {} 上锁成功", Thread.currentThread().getName(), Thread.currentThread().getId());
            return true;
        }
        return false;
    }

    public static void unlock(String key) {
        unlock(key, String.valueOf(Thread.currentThread().getId()));
    }

    public static void unlock(String key, String value) {
        // 使用lua脚本进行原子删除操作
        String checkAndDelScript =
                "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                "return redis.call('del', KEYS[1]) " +
                "else " +
                "return 0 " +
                "end";
        DefaultRedisScript<Long> script = new DefaultRedisScript<>();
        script.setResultType(Long.class);
        script.setScriptText(checkAndDelScript);
        redisTemplate.execute(script, Collections.singletonList(key), value);

    }

}
